package org.budo.graph.service.util;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.budo.graph.config.BudoGraphConfigurer;
import org.budo.support.lang.util.MapUtil;
import org.budo.support.lang.util.ReflectUtil;
import org.budo.support.lang.util.StringUtil;
import org.budo.support.spring.util.SpringUtil;
import org.springframework.context.ApplicationContext;

import com.alibaba.druid.support.json.JSONUtils;
import com.alibaba.dubbo.config.MethodConfig;
import com.alibaba.dubbo.config.ProtocolConfig;

/**
 * @author lmw
 */
public class DubboServiceUtil {
    public static String writeDubboService(ApplicationContext applicationContext, String url) {
        List<Object> serviceBeans = new ArrayList<Object>();

        String[] beanNames = applicationContext.getBeanDefinitionNames();
        for (String beanName : beanNames) {
            Object beanInstance = SpringUtil.getBean(applicationContext, beanName);
            if (null == beanInstance) {
                continue;
            }

            if (!ReflectUtil.isAssignableFrom(BudoGraphConfigurer.SERVICE_BEAN_TYPE, beanInstance.getClass().getName())) {
                continue;
            }

            serviceBeans.add(beanInstance);
        }

        if (serviceBeans.isEmpty()) {
            return "<h1>no dubbo serviceBean</h1>";
        }

        String response = "<pre>";
        int i = 1;
        for (Object serviceBean : serviceBeans) {
            response += (i++) + ". " + serviceBeanToString(serviceBean) + "\n";
        }
        return response + "</pre>";
    }

    private static String serviceBeanToString(Object serviceBean) {
        String version = (String) ReflectUtil.invokeMethod_2(BudoGraphConfigurer.SERVICE_BEAN_TYPE, "getVersion", null, serviceBean, null);
        Object _interface = ReflectUtil.invokeMethod_2(BudoGraphConfigurer.SERVICE_BEAN_TYPE, "getInterface", null, serviceBean, null);
        String response = _interface+ ":" + (null == version ? "VERSION_NULL" : version);

        List<ProtocolConfig> protocols = (List<ProtocolConfig>) ReflectUtil.invokeMethod_2(BudoGraphConfigurer.SERVICE_BEAN_TYPE, "getProtocols", null, serviceBean, null);;
        if (null != protocols && !protocols.isEmpty()) {
            List<String> protocolNames = new ArrayList<String>();
            for (ProtocolConfig protocol : protocols) {
                String name = protocol.getName();
                protocolNames.add(name);
            }
            response += ", protocols=" + protocolNames;
        }

        Integer timeout = (Integer) ReflectUtil.invokeMethod_2(BudoGraphConfigurer.SERVICE_BEAN_TYPE, "getTimeout", null, serviceBean, null);
        if (null != timeout) {
            response += ", timeout=" + timeout;
        }

        Integer executes = (Integer) ReflectUtil.invokeMethod_2(BudoGraphConfigurer.SERVICE_BEAN_TYPE, "getExecutes", null, serviceBean, null);
        if (null != executes) {
            response += ", executes=" + executes;
        }

        List<String> methodConfList = new ArrayList<String>();
        List<MethodConfig> methodConfigs = (List<MethodConfig>) ReflectUtil.invokeMethod_2(BudoGraphConfigurer.SERVICE_BEAN_TYPE, "getMethods", null, serviceBean, null);
        if (null != methodConfigs && !methodConfigs.isEmpty()) {
            for (MethodConfig methodConfig : methodConfigs) {
                methodConfList.add(methodConfigToString(methodConfig));
            }

            response += ", methods = {" + StringUtil.join(methodConfList, ",\n\t") + "}";
        }

        return response;
    }

    private static String methodConfigToString(MethodConfig methodConfig) {
        List<String> methodConf = new ArrayList<String>();
        Integer methodTimeout = methodConfig.getTimeout();
        if (null != methodTimeout) {
            methodConf.add("timeout = " + methodTimeout);
        }

        Integer methodExecutes = methodConfig.getExecutes();
        if (null != methodExecutes) {
            methodConf.add("executes = " + methodExecutes);
        }

        return methodConfig.getName() + "={" + StringUtil.join(methodConf) + "}";
    }

    public static String writeDubboServiceJson(ApplicationContext applicationContext, String url) {
        Set<Map<String, Object>> services = new HashSet<Map<String, Object>>();

        String[] beanNames = applicationContext.getBeanDefinitionNames();
        for (String beanName : beanNames) {
            Object beanInstance = SpringUtil.getBean(applicationContext, beanName, true);
            if (null == beanInstance) {
                continue;
            }

            if (!ReflectUtil.isAssignableFrom(beanInstance.getClass().getName(), BudoGraphConfigurer.SERVICE_BEAN_TYPE)) {
                continue;
            }

            String interfaceName = (String) ReflectUtil.invokeMethod_2(BudoGraphConfigurer.SERVICE_BEAN_TYPE, "getInterface", null, beanInstance, null);
            services.add(MapUtil.stringObjectMap("interface", interfaceName));
        }

        return JSONUtils.toJSONString(services);
    }
}